package com.lambkit.web.template;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;
import com.lambkit.core.Lambkit;
import com.lambkit.util.FileKit;
import com.lambkit.util.ServletRequestKit;
import com.lambkit.util.StringKit;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

public class TemplatePro implements ITemplatePro {

    @Override
    public String buildFolder(String templatePath, String templateFolderAbsolutePath) {
        String basePath = null;
        String resutPath = null;
        if(TemplateManager.me().getTemplatePathType()==TemplateManager.PATH_TYPE_RESOURCES) {
            try {
                File file = getFile(templatePath);
                if(file!=null) {
                    basePath = file.getAbsolutePath();
                    basePath = basePath.concat(File.separator);
                }
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
            resutPath = StringKit.removePrefix(templateFolderAbsolutePath, basePath);
        } else if(TemplateManager.me().getTemplatePathType()==TemplateManager.PATH_TYPE_FILE
                || TemplateManager.me().getTemplatePathType()==TemplateManager.PATH_TYPE_WEBAPP) {
            basePath = TemplateManager.me().getBaseTemplatePath() + templatePath;
            File file = new File(basePath);
            resutPath = StringKit.removePrefix(templateFolderAbsolutePath, file.getAbsolutePath());
        } else if(templatePath.startsWith(CLASSPATH_URL_PREFIX)) {
            basePath = templatePath;
            //resutPath = templateFolderAbsolutePath;
            resutPath = StringKit.removePrefix(templateFolderAbsolutePath, basePath);
        } else {
            String webRootPath = Lambkit.context().resourceService().getWebRootPath();
            webRootPath = webRootPath.replaceAll("/", Matcher.quoteReplacement(File.separator));
            webRootPath = webRootPath.replaceAll("\\\\", Matcher.quoteReplacement(File.separator));
            basePath = webRootPath
                    .concat(File.separator)
                    .concat("templates")
                    .concat(File.separator);
            resutPath = StringKit.removePrefix(templateFolderAbsolutePath, basePath);
        }
        if(resutPath.startsWith("/")) {
            resutPath = StringKit.removePrefix(resutPath, "/");
        }
        if(resutPath.endsWith("/")) {
            resutPath = StringKit.removeSuffix(resutPath, "/");
        }
        if(resutPath.startsWith("\\")) {
            resutPath = StringKit.removePrefix(resutPath, "\\");
        }
        if(resutPath.endsWith("\\")) {
            resutPath = StringKit.removeSuffix(resutPath, "\\");
        }
        if(Lambkit.context().getDevMode()) {
            //StaticLog.info("basePath: " + basePath);
            //StaticLog.info("templatePath: " + templatePath);
            //StaticLog.info("templateFolder: " + templateFolderAbsolutePath);
            //StaticLog.info("folder: " + resutPath);
            StaticLog.info("template: " + templateFolderAbsolutePath);
        }
        return resutPath;
    }

    private static final String TEMPLATE_SEPARATOR = "_";
    private static final String TEMPLATE_H5_SUFFIX = "_h5.html";


    @Override
    public void uninstall(String folder, String templatePath) {
        FileKit.deleteQuietly(new File(getAbsolutePath(folder, templatePath)));
    }
    /**
     * 找出可以用来渲染的 html 模板
     *
     * @param template
     * @return
     */
    @Override
    public String matchTemplateFile(List<String> htmls, String template, boolean isMoblieBrowser) {
        if (isMoblieBrowser) {
            int indexOf = template.indexOf(".");
            template = template.substring(0, indexOf) + TEMPLATE_H5_SUFFIX;
        }

        if (htmls.contains(template)) {
            return template;
        }

        int lastIndex = template.lastIndexOf(TEMPLATE_SEPARATOR);
        if (lastIndex <= 0) {
            return null;
        }

        //手机浏览器，优先去找_h5的模板进行渲染
        if (isMoblieBrowser) {
            String h5Template = matchH5Template(htmls, template);
            if (h5Template != null) {
                return h5Template;
            }
        }

        while (lastIndex > 0) {
            template = template.substring(0, lastIndex) + ".html";
            if (htmls.contains(template)) {
                return template;
            }
            lastIndex = template.lastIndexOf(TEMPLATE_SEPARATOR);
        }

        return htmls.contains(template) ? template : null;
    }


    /**
     * 只匹配 h5 的模板 ，如果匹配不到 h5 ，返回 null
     * <p>
     * 例如：
     * 需要 aa_bb_cc_dd_h5.html
     * 寻找的顺序是：aa_bb_cc_h5.html  ->   aa_bb_h5.html  ->   aa_h5.html
     *
     * @param template
     * @return
     */

    private String matchH5Template(List<String> htmls, String template) {
        while (StringKit.countMatches(template, '_') > 1) {

            int sLastIndex = StringKit.lastOrdinalIndexOf(template, "_", 2);
            template = template.substring(0, sLastIndex) + "_h5.html";

            if (htmls.contains(template)) {
                return template;
            }
        }

        return htmls.contains(template) ? template : null;
    }



    @Override
    public String getFolder(String folder, String mobileTpl, String wechatTpl, HttpServletRequest request) {
    	//;StaticLog.info("mobileTpl: " + mobileTpl + ", isMobile: " + RequestUtils.isMoblieBrowser(request));
        if(StrKit.notBlank(mobileTpl) && ServletRequestKit.isMobileBrowser(request)) {
    		return folder + "/" + mobileTpl;
    	} else if(StrKit.notBlank(wechatTpl) && ServletRequestKit.isWechatBrowser(request)) {
    		return folder + "/" + wechatTpl;
    	} else {
    		return folder;
    	}
    }

    @Override
    public String getAbsolutePath(String folder, String templatePath) {
        StringBuilder path;
        if(TemplateManager.me().getTemplatePathType()==TemplateManager.PATH_TYPE_RESOURCES) {
            path = new StringBuilder(templatePath).append("/").append(folder);
        } else {
            path = new StringBuilder(PathKit.getWebRootPath())
                    .append(File.separator)
                    .append("templates")
                    .append(File.separator)
                    .append(folder);
        }
        return path.toString();
    }

    @Override
    public String getWebAbsolutePath(String folder, String templatePath) {
        StringBuilder path;
        if(TemplateManager.me().getTemplatePathType()==TemplateManager.PATH_TYPE_RESOURCES) {
            path = new StringBuilder("/").append(folder);
        } else {
            path = new StringBuilder("/").append(templatePath)
                    .append("/")
                    .append(folder);
        }
        return path.toString();
    }

    /**
     * 获得某个模块下支持的样式
     * 一般用于在后台设置
     *
     * @param prefix
     * @return
     */
    @Override
    public List<String> getSupportStyles(List<String> htmls, String prefix) {
        if (prefix == null) {
            throw new IllegalArgumentException("prefix must not be null");
        }

        List<String> styles = new ArrayList<>();
        for (String html : htmls) {
            //xxx_h5.html 不算独立样式
            if (html.startsWith(prefix) && !html.contains("_h5.")) {
                styles.add(html.substring(prefix.length(), html.length() - 5));
            }
        }

        return styles;
    }

    private final String CLASSPATH_URL_PREFIX = "classpath:";

    private final String URL_PROTOCOL_FILE = "file";

    private File getFile(String resourceLocation) throws FileNotFoundException {
        notNull(resourceLocation, "Resource location must not be null");
        if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
            String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
            String description = "class path resource [" + path + "]";
            ClassLoader cl = getDefaultClassLoader();
            URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
            if (url == null) {
                throw new FileNotFoundException(description +
                        " cannot be resolved to absolute file path because it does not exist");
            }
            return getFile(url, description);
        }
        try {
            // try URL
            return getFile(new URL(resourceLocation));
        }
        catch (MalformedURLException ex) {
            // no URL -> treat as file path
            return new File(resourceLocation);
        }
    }

    private File getFile(URL resourceUrl) throws FileNotFoundException {
        return getFile(resourceUrl, "URL");
    }
    private File getFile(URL resourceUrl, String description) throws FileNotFoundException {
        notNull(resourceUrl, "Resource URL must not be null");
        if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) {
            throw new FileNotFoundException(
                    description + " cannot be resolved to absolute file path " +
                            "because it does not reside in the file system: " + resourceUrl);
        }
        try {
            return new File(toURI(resourceUrl).getSchemeSpecificPart());
        }
        catch (URISyntaxException ex) {
            // Fallback for URLs that are not valid URIs (should hardly ever happen).
            return new File(resourceUrl.getFile());
        }
    }

    private URI toURI(URL url) throws URISyntaxException {
        return toURI(url.toString());
    }

    /**
     * Create a URI instance for the given location String,
     * replacing spaces with "%20" URI encoding first.
     * @param location the location String to convert into a URI instance
     * @return the URI instance
     * @throws URISyntaxException if the location wasn't a valid URI
     */
    private URI toURI(String location) throws URISyntaxException {
        return new URI(StrUtil.replace(location, " ", "%20"));
    }

    private void notNull(Object object, String message) {
        if (object == null) {
            throw new IllegalArgumentException(message);
        }
    }

    private ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        }
        catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back...
        }
        if (cl == null) {
            // No thread context class loader -> use class loader of this class.
            cl = this.getClass().getClassLoader();
            if (cl == null) {
                // getClassLoader() returning null indicates the bootstrap ClassLoader
                try {
                    cl = ClassLoader.getSystemClassLoader();
                }
                catch (Throwable ex) {
                    // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
                }
            }
        }
        return cl;
    }
}